#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include "log.hpp"

Log log;
using func = function<string(char*)> ;
class udpserver
{
public:
    void init()
    {
        // 创建udp server
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            log(Fatal, "server create fail:%d", sockfd_);
            exit(1);
        }
        log(Debug, "server create success:%d", sockfd_);
        // bind socked
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);                  // 转化成网络字节序
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将ip转化成数字，再将数字转化为网络字节序
        if (bind(sockfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log(Fatal, "server bind fail:%d\n", sockfd_);
            exit(2);
        }
        log(Debug, "server bind success:%d\n", sockfd_);
    }

    void run()
    {
        char buf[1024] = {0};
        while (1)
        {
            struct sockaddr_in client; // 客户端的信息
            socklen_t len = sizeof(client);
            // 收数据
            ssize_t n = recvfrom(sockfd_, buf, sizeof(buf), 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                log(Warning, "receice fail, errno:%d, errno string:%s\n", errno, strerror(errno));
                continue;
            }
            //记录用户
                //获取ip字符串
            char ipbuf[1024];
            string ip = inet_ntop(AF_INET, &client, ipbuf, sizeof(ipbuf));
            if(users_.find(ip) == users_.end())
            {
                users_.insert({ip, client});
                cout << "welcome " << ip << endl;
            }
            // 向所有用户广播数据
            for(auto& e:users_)
            {
                string ret = e.first;
                ret += " say:";
                ret += buf;//[ip] say:......
                sendto(sockfd_, ret.c_str(), ret.size(), 0, (struct sockaddr *)&e.second, sizeof(e.second));
                if (n < 0)
                {
                    log(Warning, "send fail, errno:%d, errno string:%s\n", errno, strerror(errno));
                }
            }
        }
    }
    udpserver(uint16_t port = 8888, string ip = "0.0.0.0")
        : port_(port), ip_(ip)
    {
    }
    ~udpserver()
    {
        if (sockfd_ > 0)
            close(sockfd_);
    }

private:
    int sockfd_;
    uint16_t port_;
    string ip_;
    unordered_map<string, sockaddr_in> users_;//用户
};